package vboot.core.common.init;

import cn.hutool.core.lang.ClassScanner;
import org.springframework.web.bind.annotation.*;
import vboot.core.common.dao.JdbcDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.*;

@Component
public class SysApiInit {

    protected void initApi() {
        List<Yurl> codeUrlList = getScanList();
        List<String> dbUrlList = jdbcDao.findStringList("select id from sys_api_main");

        //收集最大权限位及最大权限位的最大权限码
        String sql = "select max(u.pos) as pos,max(u.code) as code from sys_api_main u where u.pos = (select max(uu.pos) from sys_api_main uu)";
        Map<String, Object> maxMap = jdbcDao.findMap(sql);
        int pos = 0;
        long code = 0;
        if (maxMap != null && maxMap.get("pos") != null) {
            pos = Integer.parseInt(String.valueOf(maxMap.get("pos")));
            code = Long.parseLong(String.valueOf(maxMap.get("code")));
        }
        //比较两个list得到insertList
        List<Object[]> insertList = new ArrayList<Object[]>();
        List<Object[]> updateList = new ArrayList<Object[]>();
        for (Yurl yurl : codeUrlList) {
            boolean flag = false;
            for (String dbUrlstr : dbUrlList) {
                if (yurl.getId().equals(dbUrlstr)) {
                    flag = true;
                    break;
                }
            }
            //插入
            if (!flag) {
                if (yurl.getType() == null) {
                    Object[] objects = new Object[7];
                    objects[0] = yurl.getId();
                    objects[1] = yurl.getPid();
                    objects[2] = 0;
                    objects[3] = 0;
                    objects[4] = yurl.getUrl();
                    objects[5] = yurl.getType();
                    objects[6] = new Date();
                    insertList.add(objects);
                } else {
                    if (code >= (1L << 62)) {
                        pos = pos + 1;
                        code = 1;
                    } else {
                        if (code == 0) {
                            code = 1;
                        } else {
                            code = code << 1;
                        }
                    }
                    Object[] objects = new Object[7];
                    objects[0] = yurl.getId();
                    objects[1] = yurl.getPid();
                    objects[2] = pos;
                    objects[3] = code;
                    objects[4] = yurl.getUrl();
                    objects[5] = yurl.getType();
                    objects[6] = new Date();
                    insertList.add(objects);
                }
            } else {//更新
                Object[] objects = new Object[3];
                objects[0] = yurl.getPid();
                objects[1] = yurl.getType();
                objects[2] = yurl.getId();
                updateList.add(objects);
            }
        }
        //设置是否为公共资源
//        for (Object[] objects : insertList) {
//            if (objects[0].toString().contains("_c")) {
//                objects[5] = 1;
//            }
//        }
        //更新数据库
        String initSql = "UPDATE sys_api_main SET avtag=0";
        String updateSql = "UPDATE sys_api_main SET pid=?,type=?,avtag=1 WHERE id=?";
        String insertSql = "INSERT INTO sys_api_main(id,pid,pos,code,url,type,crtim,avtag) VALUES(?,?,?,?,?,?,?,1)";
        jdbcDao.update(initSql);
        jdbcDao.batch(updateSql, updateList);
        jdbcDao.batch(insertSql, insertList);
        SysApiCache.AUTHPOS = pos;
        //初始化所有用户权限
        String updateUserSql = "update sys_org_user set retag=0";
        jdbcDao.update(updateUserSql);
        //将所有要求认证的权限放入application
        String g1permSql = "SELECT url,pos,code from sys_api_main where avtag=1 and type='get' and id not like '%}:get'";
        SysApiCache.GET1_APIS = getPerms(g1permSql);

        String g2permSql = "SELECT url,pos,code from sys_api_main where avtag=1 and type='get' and id like '%}:get'";
        SysApiCache.GET2_APIS = getPerms(g2permSql);

        String postUrlSql = "SELECT url,pos,code from sys_api_main where avtag=1 and type='post'";
        SysApiCache.POST_APIS = getPerms(postUrlSql);

        String putUrlSql = "SELECT url,pos,code from sys_api_main where avtag=1 and type='put'";
        SysApiCache.PUT_APIS = getPerms(putUrlSql);

        String deleteUrlSql = "SELECT url,pos,code from sys_api_main where avtag= 1 and type='delete'";
        SysApiCache.DELETE_APIS = getPerms(deleteUrlSql);

        String patchUrlSql = "SELECT url,pos,code from sys_api_main where avtag=1 and type='patch'";
        SysApiCache.PATCH_APIS = getPerms(patchUrlSql);

    }

    private List<Yurl> getScanList() {
        List<Yurl> list = new ArrayList<>();
        Set<Class<?>> classes = ClassScanner.scanPackage("vboot");

        for (Class<?> clazz : classes) {
            RequestMapping requestMapping = clazz.getAnnotation(RequestMapping.class);
            if (requestMapping != null) {
                String classUrl = requestMapping.value()[0];
                //---> /authc 开头的不需要登录， /gen 只要登录就有权限  /sys 需要管理员才有权限  其余通过rbac权限机制判断
//                if (!url.startsWith("authc")&&!url.startsWith("gen")&&!url.startsWith("sys")) {
                if (!classUrl.startsWith("authc") && !classUrl.startsWith("gen")) {
                    Yurl topUrl = new Yurl();
                    topUrl.setId(classUrl.replaceAll("/", "-"));
                    if (!classUrl.startsWith("/")) {
                        classUrl = "/" + classUrl;
                    }
                    if(topUrl.getId().contains("-")){
                        topUrl.setPid(topUrl.getId().split("-")[0]);
                    }
                    topUrl.setUrl(classUrl);
                    list.add(topUrl);
                    Method[] methods = clazz.getDeclaredMethods();
                    for (Method method : methods) {
                        GetMapping getMapping = method.getAnnotation(GetMapping.class);
                        if (getMapping != null) {
                            Yurl yurl = new Yurl();
                            String methodUrl = "";
                            if (getMapping.value().length > 0) {
                                methodUrl = getMapping.value()[0];
                                yurl.setUrl(topUrl.getUrl() + "/" + methodUrl);
                                methodUrl = methodUrl.replaceAll("/", "-");
                                yurl.setId(topUrl.getId() + "-" + methodUrl + ":get");
                            } else {
                                yurl.setId(topUrl.getId() + ":get");
                                yurl.setUrl(topUrl.getUrl());
                            }
                            yurl.setPid(topUrl.getId());
                            yurl.setType("get");
                            list.add(yurl);
                            continue;
                        }
                        PostMapping postMapping = method.getAnnotation(PostMapping.class);
                        if (postMapping != null) {
                            Yurl yurl = new Yurl();
                            String methodUrl = "";
                            if (postMapping.value().length > 0) {
                                methodUrl = postMapping.value()[0];
                                yurl.setUrl(topUrl.getUrl() + "/" + methodUrl);
                                methodUrl = methodUrl.replaceAll("/", "-");
                                yurl.setId(topUrl.getId() + "-" + methodUrl + ":post");
                            } else {
                                yurl.setId(topUrl.getId() + ":post");
                                yurl.setUrl(topUrl.getUrl());
                            }
                            yurl.setPid(topUrl.getId());
                            yurl.setType("post");
                            list.add(yurl);
                            continue;
                        }
                        PutMapping putMapping = method.getAnnotation(PutMapping.class);
                        if (putMapping != null) {
                            Yurl yurl = new Yurl();
                            String methodUrl = "";
                            if (putMapping.value().length > 0) {
                                methodUrl = putMapping.value()[0];
                                yurl.setUrl(topUrl.getUrl() + "/" + methodUrl);
                                methodUrl = methodUrl.replaceAll("/", "-");
                                yurl.setId(topUrl.getId() + "-" + methodUrl + ":put");
                            } else {
                                yurl.setId(topUrl.getId() + ":put");
                                yurl.setUrl(topUrl.getUrl());
                            }
                            yurl.setPid(topUrl.getId());
                            yurl.setType("put");
                            list.add(yurl);
                            continue;
                        }
                        DeleteMapping deleteMapping = method.getAnnotation(DeleteMapping.class);
                        if (deleteMapping != null) {
                            Yurl yurl = new Yurl();
                            String methodUrl = "";
                            if (deleteMapping.value().length > 0) {
                                methodUrl = deleteMapping.value()[0];
                                yurl.setUrl(topUrl.getUrl() + "/" + methodUrl);
                                methodUrl = methodUrl.replaceAll("/", "-");
                                yurl.setId(topUrl.getId() + "-" + methodUrl + ":delete");
                            } else {
                                yurl.setId(topUrl.getId() + ":delete");
                                yurl.setUrl(topUrl.getUrl());
                            }

                            yurl.setPid(topUrl.getId());
                            yurl.setType("delete");
                            list.add(yurl);
                            continue;
                        }
//
                        PatchMapping patchMapping = method.getAnnotation(PatchMapping.class);
                        if (patchMapping != null) {
                            Yurl yurl = new Yurl();
                            String methodUrl = "";
                            if (patchMapping.value().length > 0) {
                                methodUrl = patchMapping.value()[0];
                                yurl.setUrl(topUrl.getUrl() + "/" + methodUrl);
                                methodUrl = methodUrl.replaceAll("/", "-");
                                yurl.setId(topUrl.getId() + "-" + methodUrl + ":patch");
                            } else {
                                yurl.setId(topUrl.getId() + ":patch");
                                yurl.setUrl(topUrl.getUrl());
                            }
                            yurl.setPid(topUrl.getId());
                            yurl.setType("patch");
                            list.add(yurl);
                            continue;
                        }

                    }
                }
            }
        }
        Set<String> rootSet = new HashSet<>();

        for (Yurl yurl : list) {
            if(yurl.getType()==null&&yurl.getPid()!=null){
                rootSet.add(yurl.getPid());
            }
        }
        for (String str : rootSet) {
            Yurl yurl=new Yurl();
            yurl.setId(str);
            list.add(yurl);
        }
        return list;
    }

    private List<Yapi> getPerms(String sql) {
        return jdbcDao.getTp().query(sql, (rs, rowNum) -> {
            Yapi yperm = new Yapi();
            String url = rs.getString("url");
            if (url.endsWith("}")) {
                yperm.setUrl(url.substring(0, url.lastIndexOf("/")));
            } else {
                yperm.setUrl(url);
            }
            yperm.setPos(rs.getInt("pos"));
            yperm.setCode(rs.getLong("code"));
            return yperm;
        });
    }

    @Autowired
    private JdbcDao jdbcDao;


}